// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_image.h"
#include "mk_memory_block.h"
#include "mk_engine.h"
#include "mk_file_system.h"
#include "mk_error.h"

namespace MK3DE
{
	CImage::CImage(const char* fileName) : CResource(fileName)
	{
		_imageID = 0;
	}

	CImage::~CImage()
	{
		if (_imageID)
			ilDeleteImage(_imageID);
	}

	BOOL CImage::Load()
	{
		_imageID = ilGenImage();
		ilBindImage(_imageID);

		BOOL ret = FALSE;
		ILboolean bRet = 0;
		CMemoryBlock block;
		ret = GetEngine()->GetFileSystem()->ReadFile(_fileName.c_str(), &block);
		MK_PROCESS_ERROR(ret);

		bRet = ilLoadL(IL_TYPE_UNKNOWN, (const void*)block.GetBuffer(), (ILuint)block.GetSize());
		MK_PROCESS_ERROR(bRet);

		ret = TRUE;
Exit0:
		return ret;
	}

	DWORD CImage::GetWidth()
	{
		if (!_imageID)
			return 0;

		ilBindImage(_imageID);
		return (DWORD)ilGetInteger(IL_IMAGE_WIDTH);
	}

	DWORD CImage::GetHeight()
	{
		if (!_imageID)
			return 0;

		ilBindImage(_imageID);
		return (DWORD)ilGetInteger(IL_IMAGE_HEIGHT);
	}

	BYTE* CImage::GetData()
	{
		if (!_imageID)
			return NULL;

		ilBindImage(_imageID);
		return (BYTE*)ilGetData();
	}

	DWORD CImage::GetBpp()
	{
		if (!_imageID)
			return 0;

		ilBindImage(_imageID);
		return (DWORD)ilGetInteger(IL_IMAGE_BPP);
	}

	BOOL CImage::Scale(DWORD width, DWORD height)
	{
		if (!_imageID)
			return FALSE;

		return iluScale((ILuint)width, (ILuint)height, ilGetInteger(IL_IMAGE_DEPTH)) ? TRUE : FALSE;
	}

	PIXEL_FORMAT CImage::GetFormat()
	{
		if (!_imageID)
			return PF_UNKNOWN;

		ILuint format = ilGetInteger(IL_IMAGE_FORMAT);
		ILuint type = ilGetInteger(IL_IMAGE_TYPE);
		return __MappingFormat(format, type);
	}

	BOOL CImage::ConvertFormat(PIXEL_FORMAT format)
	{
		ILuint fmt;
		ILuint type;
		BOOL ret = FALSE;
		ILboolean ilRet = 0;

		MK_PROCESS_ERROR(_imageID);

		ret = __MappingFormat(format, fmt, type);
		MK_PROCESS_ERROR(ret);

		ilRet = ilConvertImage(fmt, type);
		MK_PROCESS_ERROR(ilRet);

		ret = TRUE;
Exit0:
		return ret;
	}

	PIXEL_FORMAT CImage::__MappingFormat(ILuint format, ILuint type)
	{
		if (format == IL_RGB && type == IL_UNSIGNED_BYTE)
			return PF_R8G8B8;
		else if (format == IL_RGBA && type  == IL_UNSIGNED_BYTE)
			return PF_R8G8B8A8;
		else if (format == IL_LUMINANCE && type == IL_UNSIGNED_BYTE)
			return PF_L8;
		else if (format == IL_LUMINANCE_ALPHA && type == IL_UNSIGNED_BYTE)
			return PF_A8;
		else if (format == IL_LUMINANCE && type == IL_FLOAT)
			return PF_R32F;
		else
			return PF_UNKNOWN;
	}

	BOOL CImage::__MappingFormat(PIXEL_FORMAT fmt, ILuint& format, ILuint& type)
	{
		switch (fmt)
		{
		case PF_R8G8B8:
			{
				format = IL_RGB;
				type = IL_UNSIGNED_BYTE;
			}
			break;

		case PF_R8G8B8A8:
			{
				format = IL_RGBA;
				type = IL_UNSIGNED_BYTE;
			}
			break;

		case PF_L8:
			{
				format = IL_LUMINANCE;
				type = IL_UNSIGNED_BYTE;
			}
			break;

		case  PF_A8:
			{
				format = IL_LUMINANCE_ALPHA;
				type = IL_UNSIGNED_BYTE;
			}
			break;

		case PF_R32F:
			{
				format = IL_LUMINANCE;
				type = IL_FLOAT;
			}
			break;

		default:
			return FALSE;
		};

		return TRUE;
	}
}